<template>
  <el-form
    :model="formData"
    ref="formRef"
    :label-width="schema.labelWidth || '100px'"
  >
    <template v-for="field in schema.fields" :key="field.field">
      <el-form-item
        v-if="isVisible(field)"
        :label="field.label"
        :prop="field.field"
        :rules="getRules(field)"
      >
        <!-- 嵌套字段单独处理 -->
        <template v-if="field.type === 'nested'">
          <div
            v-for="(item, i) in formData[field.field]"
            :key="i"
            style="margin-bottom: 10px"
          >
            <el-form-item
              v-for="child in field.children"
              :key="child.field"
              :label="child.label"
              :prop="`${field.field}.${i}.${child.field}`"
              :rules="getRules(child)"
              style="margin-bottom: 8px"
            >
              <component
                :is="getComponent(child)"
                v-model="formData[field.field][i][child.field]"
                :placeholder="'请输入' + child.label"
                style="width: 200px"
                v-bind="getExtraProps(child)"
              />
            </el-form-item>
            <el-button
              @click="removeNested(field, i)"
              type="danger"
              size="small"
              >删除</el-button
            >
          </div>
          <el-button @click="addNested(field)" type="primary" size="small"
            >添加{{ field.label }}</el-button
          >
        </template>

        <!-- 普通类型 -->
        <component
          v-else
          :is="getComponent(field)"
          v-model="formData[field.field]"
          :placeholder="'请输入' + field.label"
          style="width: 220px"
          v-bind="getExtraProps(field)"
        >
          <!-- 下拉选项 -->
          <template v-if="['select', 'multiselect'].includes(field.type)">
            <el-option
              v-for="opt in field.options || []"
              :key="opt"
              :label="opt"
              :value="opt"
            />
          </template>
        </component>
      </el-form-item>
    </template>

    <el-form-item>
      <el-button type="primary" @click="submit">提交</el-button>
      <el-button @click="reset" style="margin-left: 8px">重置</el-button>
    </el-form-item>
  </el-form>
</template>

<script setup>
import { ref, reactive, watch } from "vue";
import { ElMessage } from "element-plus";

// Props
const props = defineProps({
  schema: { type: Object, required: true },
  modelValue: { type: Object, default: () => ({}) },
});
const emit = defineEmits(["update:modelValue"]);

// 表单数据
const formRef = ref();
const formData = reactive({});

// 初始化 formData，支持嵌套字段
function initFormData(fields, data) {
  fields.forEach((field) => {
    if (field.type === "nested") {
      if (!formData[field.field]) formData[field.field] = [];
    } else {
      formData[field.field] = data[field.field] ?? "";
    }
  });
}
initFormData(props.schema.fields, props.modelValue);

// 双向绑定
watch(formData, (val) => emit("update:modelValue", val), { deep: true });

// 显隐逻辑
function isVisible(field) {
  if (!field.visibleWhen) return true;
  const { field: depField, value } = field.visibleWhen;
  return formData[depField] === value;
}

// 校验规则
function getRules(field) {
  const rules = [];
  if (field.required) {
    rules.push({
      required: true,
      message: `${field.label}为必填项`,
      trigger: "blur",
    });
  }
  if (field.validateType) {
    const preset = {
      email: {
        pattern: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
        message: "请输入正确的邮箱",
      },
      phone: { pattern: /^1[3-9]\d{9}$/, message: "请输入有效手机号" },
      number: { pattern: /^[0-9]+$/, message: "只能输入数字" },
    };
    if (preset[field.validateType]) {
      rules.push({
        pattern: preset[field.validateType].pattern,
        message: preset[field.validateType].message,
        trigger: "blur",
      });
    }
  }
  return rules;
}

// 组件映射
function getComponent(field) {
  switch (field.type) {
    case "input":
      return "el-input";
    case "textarea":
      return "el-input";
    case "number":
      return "el-input-number";
    case "select":
      return "el-select";
    case "multiselect":
      return "el-select";
    case "date":
      return "el-date-picker";
    case "switch":
      return "el-switch";
    case "rate":
      return "el-rate";
    default:
      return "el-input";
  }
}
function getExtraProps(field) {
  switch (field.type) {
    case "textarea":
      return { type: "textarea", rows: 3 };
    case "multiselect":
      return { multiple: true, collapseTags: true };
    case "date":
      return { type: "date", format: "YYYY-MM-DD" };
    default:
      return {};
  }
}

// 嵌套表单
function addNested(field) {
  if (!formData[field.field]) formData[field.field] = [];
  const newItem = {};
  field.children.forEach((f) => (newItem[f.field] = ""));
  formData[field.field].push(newItem);
}
function removeNested(field, idx) {
  formData[field.field].splice(idx, 1);
}

// 暴露方法
defineExpose({ submit, reset, formRef });
function submit() {
  formRef.value.validate((valid) => {
    if (valid) {
      ElMessage.success("提交成功");
      console.log("提交数据", JSON.parse(JSON.stringify(formData)));
    } else {
      ElMessage.error("校验不通过");
    }
  });
}
function reset() {
  Object.keys(formData).forEach((k) => {
    if (Array.isArray(formData[k])) formData[k] = [];
    else formData[k] = "";
  });
}
</script>
